﻿using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace CMS6Tools.Common.TFS
{
    // we can still use the same WebAccessProxy for both 2013 and 2015
    public class WebAccessProxy : IWebAccessProxy
    {
        private readonly string _tfsVersion = "2013";
        public WebAccessProxy(string tfsverion)
        {
            _tfsVersion = tfsverion;
        }

        private static readonly string _getCapacityUrl = "{0}/{1}/_backlogs/capacity/{2}";
        private static readonly string _teamCapacityStartToken = "{\"TeamCapacity\":{";
        private static readonly string _teamCapacityEndToken = "</script>";
        private static readonly string _updateCapacityUrl = "{0}/{1}/_api/_teamcapacity/updateteamcapacity/{2}?__v=1";
        private static readonly string _updateCapacityUrlLocal = "{0}/{1}/_api/_teamcapacity/updateteamcapacity/{2}?__v=1";
        private static readonly string _capacityTeamDaysOffDates = "{{\"Start\":\"\\/Date({0})\\/\",\"End\":\"\\/Date({1})\\/\"}}";
        private static readonly string _capacityTeamDaysOffDatesLocal = "{{\"Start\":\"\\/Date({0})\\/\",\"End\":\"\\/Date({1})\\/\",\"validationGroupName\":\"validation-group0\"}}";
        private static readonly string _capacityDaysOffDates = "{{\"Start\":\"\\/Date({0})\\/\",\"End\":\"\\/Date({1})\\/\"}}";
        private static readonly string _capacityDaysOffDatesLocal = "{{\"Start\":\"\\/Date({0})\\/\",\"End\":\"\\/Date({1})\\/\",\"validationGroupName\":\"validation-group1\"}}";
        private static readonly string _capacityData = "{{\"TeamDaysOffDates\":[{0}],\"TeamMemberCapacityCollection\":[{1}]}}";
        private static readonly string _capacitySaveData = "saveData={0}";
        private static readonly string _capacitySaveSuccess = "{\"success\":true}";
        private static readonly string _capacityTeamMemberCapacity = "{{\"TeamMemberId\":\"{0}\",\"Capacity\":{1},\"DaysOffDates\":[{2}],\"Activity\":\"{3}\"}}";
        private static readonly string _capacityTeamMemberCapacityLocal = "{{\"TeamMemberId\":\"{0}\",\"Capacity\":{1},\"DaysOffDates\":[{2}],\"Activity\":\"{3}\",\"DisplayName\":\"{4}\"}}";
        private static readonly string _capacityEncodedData = "{0}&__RequestVerificationToken={1}";
        private readonly string _verificationCookieName = "__RequestVerificationToken";
        private readonly string _verificationTokenStart = "<input name=\"__RequestVerificationToken\" type=\"hidden\" value=\"";
        private readonly string _verificationTokenEnd = "\" />";

        public Team GetTeamCapacitySettings(Project project, string teamName, bool isDefaultTeam, string iterationPath, string iterationID)
        {
            if (project == null)
            {
                throw new ArgumentNullException("project");
            }
            if (string.IsNullOrEmpty(iterationPath))
            {
                throw new ArgumentException("iterationPath");
            }
            var result = default(Team);
            int num = project.FindNode(iterationPath, Node.TreeType.Iteration);
            if (num != -1)
            {
                string iterationPathUrl = iterationPath.Replace(project.Name + "\\", "");
                iterationPathUrl = iterationPathUrl.Replace("\\", "/");

                TfsTeamProjectCollection teamProjectCollection = project.Store.TeamProjectCollection;
                string arg = HttpUtility.UrlPathEncode(isDefaultTeam ? project.Name : (project.Name + "/" + teamName));
                string arg2 = HttpUtility.UrlPathEncode(iterationPathUrl.Replace('\\', '/'));
                string requestUriString = string.Format(WebAccessProxy._getCapacityUrl, teamProjectCollection.Uri, arg, arg2);

                HttpWebRequest httpWebRequest = WebRequest.Create(requestUriString) as HttpWebRequest;
                httpWebRequest.Credentials = teamProjectCollection.Credentials;
                httpWebRequest.Method = "GET";
                httpWebRequest.ContentType = "text/html";

                FederatedCookieHelper.EnsureFederatedIdentityCookies(teamProjectCollection, httpWebRequest);

                try
                {
                    HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
                    Stream responseStream = httpWebResponse.GetResponseStream();
                    byte[] array = new byte[httpWebResponse.ContentLength];
                    string source = null;
                    using (StreamReader streamReader = new StreamReader(responseStream))
                    {
                        source = streamReader.ReadToEnd();
                    }
                    string substring = source.GetSubstring(WebAccessProxy._teamCapacityStartToken, WebAccessProxy._teamCapacityEndToken, false);
                    if (!string.IsNullOrEmpty(substring))
                    {
                        using (MemoryStream memoryStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(substring)))
                        {
                            var serializer = new DataContractJsonSerializer(typeof(Team));
                            result = serializer.ReadObject(memoryStream) as Team;
                        }
                        result.ConvertMultipleActivityToSingle();
                    }
                }
                catch (Exception)
                {
                    throw;
                }
            }
            return result;
        }

        private void SetTeamCapacitySettings(Project project, string teamName, bool isDefaultTeam, string iterationPath, Team team)
        {
            TfsTeamProjectCollection teamProjectCollection = project.Store.TeamProjectCollection;

            string arg = HttpUtility.UrlPathEncode(isDefaultTeam ? project.Name : (project.Name + "/" + teamName));

            string iterationPathUrl = iterationPath.Replace(project.Name + "\\", "");
            iterationPathUrl = HttpUtility.UrlPathEncode(iterationPathUrl.Replace("\\", "/"));

            string updateUrl = string.Format(teamProjectCollection.IsTfsService() ? WebAccessProxy._updateCapacityUrl : WebAccessProxy._updateCapacityUrlLocal, teamProjectCollection.Uri, arg, iterationPathUrl);

            List<string> teamDaysOffList = new List<string>();
            if (team.TeamCapacity.TeamDaysOffDates != null)
            {
                foreach (DaysOffDates daysOffDate in team.TeamCapacity.TeamDaysOffDates)
                {
                    string item = string.Format(teamProjectCollection.IsTfsService() ? WebAccessProxy._capacityTeamDaysOffDates : WebAccessProxy._capacityTeamDaysOffDatesLocal, this.GetTfsTicks(daysOffDate.Start), this.GetTfsTicks(daysOffDate.End));
                    teamDaysOffList.Add(item);
                }
            }

            CultureInfo cultureInfo = CultureInfo.GetCultureInfo(1033);
            List<string> teamMemberList = new List<string>();
            foreach (var teamMember in team.TeamCapacity.TeamMemberCapacityCollection)
            {
                List<string> list6 = new List<string>();
                if (teamMember.DaysOffDates != null)
                {
                    foreach (DaysOffDates daysOffDate in teamMember.DaysOffDates)
                    {
                        string item2 = string.Format(teamProjectCollection.IsTfsService() ? WebAccessProxy._capacityDaysOffDates : WebAccessProxy._capacityDaysOffDatesLocal, this.GetTfsTicks(daysOffDate.Start), this.GetTfsTicks(daysOffDate.End));
                        list6.Add(item2);
                    }
                }

                string item3;
                if (teamProjectCollection.IsTfsService())
                {
                    item3 = string.Format(WebAccessProxy._capacityTeamMemberCapacity, new object[]
				{
					teamMember.TeamMemberId,
					teamMember.Capacity.ToString(cultureInfo),
					string.Join(",", list6),
					teamMember.Activity
				});
                }
                else
                {
                    item3 = string.Format(WebAccessProxy._capacityTeamMemberCapacityLocal, new object[]
				{
					teamMember.TeamMemberId,
					teamMember.Capacity.ToString(cultureInfo),
					string.Join(",", list6),
					teamMember.Activity,
					teamMember.DisplayName
				});
                }
                teamMemberList.Add(item3);
            }

            string text = string.Format(WebAccessProxy._capacityData, string.Join(",", teamDaysOffList), string.Join(",", teamMemberList));
            text = string.Format(WebAccessProxy._capacitySaveData, HttpUtility.UrlEncode(text));
            string url = string.Format(WebAccessProxy._getCapacityUrl, teamProjectCollection.Uri, arg, iterationPathUrl);
            Cookie cookie;
            string text2;
            this.PrepareRequestData(url, teamProjectCollection, out cookie, out text2);
            if (cookie == null)
            {
                throw new ArgumentNullException("cookie");
            }
            if (string.IsNullOrEmpty(text2))
            {
                throw new ArgumentNullException("verificationToken");
            }
            string encodedData = string.Format(WebAccessProxy._capacityEncodedData, text, HttpUtility.UrlEncode(text2));
            string text3 = this.UpdateData(teamProjectCollection, updateUrl, cookie, encodedData);
            if (!text3.Equals(WebAccessProxy._capacitySaveSuccess))
            {
                throw new HttpException("Capacity Save failed");
            }
        }

        private void PrepareRequestData(string url, TfsTeamProjectCollection server, out Cookie cookie, out string validationToken)
        {
            cookie = null;
            validationToken = string.Empty;
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            HttpWebRequest httpWebRequest = WebRequest.Create(url) as HttpWebRequest;
            httpWebRequest.Credentials = server.Credentials;
            httpWebRequest.Method = "GET";
            httpWebRequest.ContentType = "text/html";
            FederatedCookieHelper.EnsureFederatedIdentityCookies(server, httpWebRequest);
            try
            {
                HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
                Stream responseStream = httpWebResponse.GetResponseStream();
                byte[] array = new byte[httpWebResponse.ContentLength];
                string text = null;
                if (httpWebResponse.Cookies != null)
                {
                    IEnumerable<Cookie> source = httpWebResponse.Cookies.OfType<Cookie>();
                    if (server.IsTfsService())
                    {
                        cookie = source.FirstOrDefault((Cookie c) => c.Name != null && c.Name.Equals(this._verificationCookieName));
                    }
                    else
                    {
                        cookie = source.FirstOrDefault((Cookie c) => c.Name != null && c.Name.StartsWith(this._verificationCookieName));
                    }
                    using (StreamReader streamReader = new StreamReader(responseStream))
                    {
                        text = streamReader.ReadToEnd();
                    }
                    if (!string.IsNullOrEmpty(text))
                    {
                        validationToken = text.GetSubstring(this._verificationTokenStart, this._verificationTokenEnd, true);
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        private string UpdateData(TfsTeamProjectCollection server, string updateUrl, Cookie tfsCookie, string encodedData)
        {
            HttpWebRequest httpWebRequest = WebRequest.Create(updateUrl) as HttpWebRequest;
            httpWebRequest.CookieContainer = new CookieContainer();
            httpWebRequest.CookieContainer.Add(tfsCookie);
            httpWebRequest.Method = "POST";
            httpWebRequest.Credentials = server.Credentials;
            httpWebRequest.ContentType = "application/x-www-form-urlencoded";
            byte[] bytes = Encoding.ASCII.GetBytes(encodedData);
            httpWebRequest.ContentLength = (long)bytes.Length;
            FederatedCookieHelper.EnsureFederatedIdentityCookies(server, httpWebRequest);
            Stream requestStream = httpWebRequest.GetRequestStream();
            requestStream.Write(bytes, 0, bytes.Length);
            requestStream.Close();
            string result;
            try
            {
                HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;
                Stream responseStream = httpWebResponse.GetResponseStream();
                long contentLength = httpWebResponse.ContentLength;
                byte[] array = new byte[contentLength];
                responseStream.Read(array, 0, array.Length);
                string @string = Encoding.UTF8.GetString(array);
                result = @string;
            }
            catch (WebException ex)
            {
                string text = ex.Response.Headers.GetValues("X-TFS-ServiceError")[0];
                result = text;
            }
            return result;
        }

        private double GetTfsTicks(DateTime dt)
        {
            CustomTimeZone customTimeZone = new CustomTimeZone(TimeZoneInfo.Utc);
            DateTime dateTime = new DateTime(1970, 1, 1);
            TimeSpan timeSpan = new TimeSpan(customTimeZone.ToUniversalTime(dt).Ticks - dateTime.Ticks);
            return timeSpan.TotalMilliseconds;
        }
    }
}
